package com.boot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.annotation.RateLimit;
import com.boot.config.AdminCredentialManager;
import com.boot.config.AdminCredentials;
import com.boot.config.TokenStore;
import com.boot.constants.StatusConstants;
import com.boot.entity.User;
import com.boot.service.IUserService;
import com.boot.service.LoginAttemptService;
import com.boot.service.MailService;
import com.boot.utils.JwtUtil;
import com.boot.utils.PasswordGenerator;
import com.boot.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/user")
@Slf4j
public class UserController {

    @Resource
    private IUserService userService;

    @Resource
    private MailService mailService;

    @Resource
    private TokenStore tokenStore;

    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    // 新增用户
    @RateLimit(limit = 10, windowSec = 60)
    @PostMapping("/add")
    public R<User> addUser(@RequestBody User user) {
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            return R.error("用户名不能为空");
        }
        if (userService.getOne(new QueryWrapper<User>().eq("username", user.getUsername())) != null) {
            return R.error("用户名已存在");
        }
        String email = user.getEmail();

        // 生成安全密码
        String rawPassword = PasswordGenerator.generateSecurePassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);

        user.setPassword(encodedPassword);
        user.setStatus(StatusConstants.UserStatus.ENABLED);
        user.setCreatedAt(LocalDateTime.now());
        user.setEmail(email);

        boolean saved = userService.save(user);
        if (saved && email != null && !email.trim().isEmpty()) {
            try {
                String subject = "欢迎加入系统 - 账户已创建";
                String content = buildWelcomeEmail(user.getUsername(), rawPassword);
                mailService.sendHtmlMail(email, subject, content);
            } catch (Exception e) {
                log.error("【邮件发送失败】新建用户: " + email + ", 错误: " + e.getMessage(), e);
            }
        }
        return saved ? R.success(user) : R.error("保存失败");
    }

    // 重置密码
    @RateLimit(limit = 10, windowSec = 60)
    @PutMapping("/reset-password/{id}")
    public R<Void> resetPassword(@PathVariable Long id) {
        User user = userService.getById(id);
        if (user == null) {
            return R.error("用户不存在");
        }

        String email = user.getEmail();

        // 生成新密码
        String rawPassword = PasswordGenerator.generateSecurePassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);

        user.setPassword(encodedPassword);
        boolean updated = userService.updateById(user);

        tokenStore.revokeAllTokensForUser(user.getId());

        if (updated && email != null && !email.trim().isEmpty()) {
            try {
                String subject = "您的密码已重置";
                String content = buildResetPasswordEmail(user.getUsername(), rawPassword);
                mailService.sendHtmlMail(email, subject, content);
            } catch (Exception e) {
                log.error("【邮件发送失败】密码重置: " + email + ", 错误: " + e.getMessage(), e);
            }
        }
        return updated ? R.success(null) : R.error("操作失败");
    }

    // 查询所有用户（分页）
    @RateLimit(limit = 20, windowSec = 60)
    @GetMapping("/list")
    public R<IPage<User>> listUsers(
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(required = false) String username) {

        Page<User> page = new Page<>(pageNum, pageSize);
        QueryWrapper<User> wrapper = new QueryWrapper<>();

        if (username != null && !username.trim().isEmpty()) {
            wrapper.like("username", username);
        }

        wrapper.orderByDesc("created_at");

        IPage<User> result = userService.page(page, wrapper);
        return R.page(result);
    }

    // 禁用用户
    @RateLimit(limit = 10, windowSec = 60)
    @PutMapping("/disable/{id}")
    public R<Void> disableUser(@PathVariable Long id) {
        User user = userService.getById(id);
        if (user == null) {
            return R.error("用户不存在");
        }
        user.setStatus(StatusConstants.UserStatus.DISABLED);
        boolean updated = userService.updateById(user);

        tokenStore.revokeAllTokensForUser(user.getId());

        // 发送禁用通知邮件
        String email = user.getEmail();
        if (updated && email != null && !email.trim().isEmpty()) {
            try {
                String subject = "您的账户已被禁用";
                String content = buildDisabledEmail(user.getUsername());
                mailService.sendHtmlMail(email, subject, content);
            } catch (Exception e) {
                log.error("【邮件发送失败】账户禁用通知: " + email + ", 错误: " + e.getMessage(), e);
            }
        }

        return R.success(null);
    }

    // 启用用户
    @RateLimit(limit = 10, windowSec = 60)
    @PutMapping("/enable/{id}")
    public R<Void> enableUser(@PathVariable Long id) {
        User user = userService.getById(id);
        if (user == null) {
            return R.error("用户不存在");
        }
        user.setStatus(StatusConstants.UserStatus.ENABLED);
        boolean updated = userService.updateById(user);

        tokenStore.revokeAllTokensForUser(user.getId());

        // 发送启用通知邮件
        String email = user.getEmail();
        if (updated && email != null && !email.trim().isEmpty()) {
            try {
                String subject = "您的账户已恢复启用";
                String content = buildEnabledEmail(user.getUsername());
                mailService.sendHtmlMail(email, subject, content);
            } catch (Exception e) {
                log.error("【邮件发送失败】账户启用通知: " + email + ", 错误: " + e.getMessage(), e);
            }
        }

        return R.success(null);
    }

    // 构建欢迎邮件内容
    private String buildWelcomeEmail(String username, String password) {
        return "<div style='font-family: Arial, sans-serif; padding: 20px; border: 1px solid #ddd; border-radius: 8px; max-width: 600px; margin: auto;'>"
                    + "<h2 style='color: #4CAF50;'>🎉 欢迎加入系统</h2>"
                    + "<p><strong>您好，" + username + "：</strong></p>"
                    + "<p>您的账户已成功创建，以下是登录信息，请妥善保管：</p>"
                    + "<table style='width:100%; border-collapse: collapse; margin: 20px 0;'>"
                        + "<tr><td style='padding: 8px; border: 1px solid #ccc; width: 30%;'><strong>用户名</strong></td>"
                        + "<td style='padding: 8px; border: 1px solid #ccc;'>" + username + "</td></tr>"
                        + "<tr><td style='padding: 8px; border: 1px solid #ccc;'><strong>初始密码</strong></td>"
                        + "<td style='padding: 8px; border: 1px solid #ccc; color: red; font-weight: bold;'>" + password + "</td></tr>"
                    + "</table>"
                    + "<p style='color: #d32f2f;'>⚠️ 重要提示：请登陆系统验证！</p>"
                    + "<p>如有疑问，请联系管理员。</p>"
                    + "<footer style='margin-top: 30px; color: #777; font-size: 0.9em; text-align: center;'>"
                    + "&copy; " + java.time.LocalDate.now().getYear() + " 系统管理平台</footer>"
                + "</div>";
    }

    // 构建密码重置邮件内容
    private String buildResetPasswordEmail(String username, String password) {
        return "<div style='font-family: Arial, sans-serif; padding: 20px; border: 1px solid #ddd; border-radius: 8px; max-width: 600px; margin: auto;'>"
                    + "<h2 style='color: #FF9800;'>🔑 密码已重置</h2>"
                    + "<p><strong>尊敬的用户 " + username + "：</strong></p>"
                    + "<p>您的密码已被管理员重置，新密码如下：</p>"
                    + "<table style='width:100%; border-collapse: collapse; margin: 20px 0;'>"
                        + "<tr><td style='padding: 8px; border: 1px solid #ccc; width: 30%;'><strong>用户名</strong></td>"
                        + "<td style='padding: 8px; border: 1px solid #ccc;'>" + username + "</td></tr>"
                        + "<tr><td style='padding: 8px; border: 1px solid #ccc;'><strong>新密码</strong></td>"
                        + "<td style='padding: 8px; border: 1px solid #ccc; color: red; font-weight: bold;'>" + password + "</td></tr>"
                    + "</table>"
                    + "<p style='color: #d32f2f;'>⚠️ 请登陆系统验证。</p>"
                    + "<p>此操作不可撤销，如非本人操作，请尽快联系管理员。</p>"
                    + "<footer style='margin-top: 30px; color: #777; font-size: 0.9em; text-align: center;'>"
                    + "&copy; " + java.time.LocalDate.now().getYear() + " 系统管理平台</footer>"
                + "</div>";
    }

    // 构建用户被禁用邮件内容
    private String buildDisabledEmail(String username) {
        return "<div style='font-family: Arial, sans-serif; padding: 20px; border: 1px solid #ddd; border-radius: 8px; max-width: 600px; margin: auto;'>"
                    + "<h2 style='color: #f44336;'>❌ 账户已被禁用</h2>"
                    + "<p><strong>尊敬的 " + username + "：</strong></p>"
                    + "<p>您的账户已被系统管理员禁用，暂时无法登录系统。</p>"
                    + "<p>如有疑问，请联系系统管理员以获取更多信息。</p>"
                    + "<p style='color: #555;'>感谢您的理解与配合。</p>"
                    + "<footer style='margin-top: 30px; color: #777; font-size: 0.9em; text-align: center;'>"
                    + "&copy; " + java.time.LocalDate.now().getYear() + " 系统管理平台</footer>"
                + "</div>";
    }

    // 构建用户被启用邮件内容
    private String buildEnabledEmail(String username) {
        return "<div style='font-family: Arial, sans-serif; padding: 20px; border: 1px solid #ddd; border-radius: 8px; max-width: 600px; margin: auto;'>"
                    + "<h2 style='color: #4CAF50;'>✅ 账户已恢复</h2>"
                    + "<p><strong>您好，" + username + "：</strong></p>"
                    + "<p>您的账户已被系统管理员成功启用，现在可以正常登录系统。</p>"
                    + "<p>欢迎继续使用我们的服务！</p>"
                    + "<footer style='margin-top: 30px; color: #777; font-size: 0.9em; text-align: center;'>"
                    + "&copy; " + java.time.LocalDate.now().getYear() + " 系统管理平台</footer>"
                + "</div>";
    }

    @Resource
    private LoginAttemptService loginAttemptService;

    @Resource
    private AdminCredentialManager adminCredentialManager;

    @Resource
    private JwtUtil jwtUtil;

    /**
     * 用户登录接口
     */
    @PostMapping("/login")
    @RateLimit(limit = 5, windowSec = 60)
    public R<Map<String, String>> login(@Valid @RequestBody LoginRequest request, HttpServletRequest httpServletRequest) {
        String clientIp = getClientIp(httpServletRequest);
        String username = request.getUsername();
        String password = request.getPassword();

        // 1. 检查 IP 是否被锁定
        if (loginAttemptService.isBlocked(clientIp)) {
            log.warn("IP {} 已被锁定，拒绝登录", clientIp);
            return R.error("登录失败次数过多，该IP已被暂时锁定，请15分钟后重试");
        }

        // 2. 获取当前有效的管理员凭据（内存中）
        AdminCredentials validCreds = adminCredentialManager.getCredentials();

        // 3. 校验用户名和密码
        if (!username.equals(validCreds.getUsername()) || !passwordEncoder.matches(password, validCreds.getEncodedPassword())) {
            loginAttemptService.loginFailed(clientIp);
            return R.error("用户名或密码错误");
        }

        // 4. 登录成功：清除尝试记录
        loginAttemptService.loginSuccess(clientIp);

        // 5. 生成 JWT Token（使用固定 userId = -1 表示管理员）
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", -1L);           // 特殊标识
        claims.put("username", username);
        claims.put("role", "admin");

        String token = jwtUtil.generateToken(claims);

        // 6. 存入 Redis（支持登出）
        tokenStore.saveToken(token, -1L);

        // 7. 返回响应
        Map<String, String> result = new HashMap<>();
        result.put("token", token);
        result.put("username", username);

        log.info("管理员登录成功 [{}], IP={}", username, clientIp);
        return R.success(result);
    }

    // 辅助方法：获取客户端IP
    private String getClientIp(HttpServletRequest request) {
        String xff = request.getHeader("X-Forwarded-For");
        if (xff != null && !xff.isEmpty() && !"unknown".equalsIgnoreCase(xff)) {
            return xff.split(",")[0].trim();
        }
        String xri = request.getHeader("X-Real-IP");
        if (xri != null && !xri.isEmpty() && !"unknown".equalsIgnoreCase(xri)) {
            return xri.trim();
        }
        return request.getRemoteAddr();
    }

    // 登录请求 DTO
    public static class LoginRequest {
        private String username;
        private String password;

        // getter/setter
        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    /**
     * token校验接口
     */
    @RateLimit(limit = 100, windowSec = 60)
    @PostMapping("/check")
    public R<Boolean> check(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null) {
            return R.success(false);
        }

        String token = null;
        if (authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
        }

        if (token != null && tokenStore.isValid(token)) {
            return R.success(true);
        }

        return R.success(false);
    }
}
